package com.hzdaba.aiapi.handlerInterceptor;

import com.hzdaba.aiapi.properties.ReqIdKeyProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;

/**
 * 校验 请求 id
 *
 * @author 刘逸晖
 */
@Component
public class CheckReqIdHandlerInterceptor implements HandlerInterceptor {

    /**
     * 访问 Redis
     */
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    /**
     * 请求 id 相关配置
     */
    @Autowired
    private ReqIdKeyProperties reqIdKeyProperties;

    /**
     * 请求 id 对应的参数名
     */
    @Value("${aiapi.reqid.request.parameter.name}")
    private String nameOfReqId;

    /**
     * 请求中存放错误信息的 key
     */
    @Value("${aiapi.request.attribute.error.key}")
    private String keyOfError;

    /**
     * 日志记录器
     */
    private static final Logger logger = LoggerFactory.getLogger(CheckReqIdHandlerInterceptor.class);

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //获取参数值
        String reqId = request.getParameter(this.nameOfReqId);

        if (reqId == null || reqId.length() == 0) {
            response.setStatus(403);
            request.setAttribute(this.keyOfError, "请携带请求 id");
            request.getRequestDispatcher("/error/error").forward(request, response);

//            CheckReqIdHandlerInterceptor.logger.info("没有携带请求 id ，不与访问");
            return false;
        }

        //检查 Redis 中是否有缓存这个请求 id
        Boolean isHad = this.redisTemplate.opsForHash().hasKey(this.reqIdKeyProperties.getPrefix(), reqId);

        if (isHad != null && isHad) {//reqId 重复了，拒绝访问
            response.setStatus(403);
            request.setAttribute(this.keyOfError, "抱歉，请求 id 重复了");
            request.getRequestDispatcher("/error/error").forward(request, response);

//            CheckReqIdHandlerInterceptor.logger.info("请求 id 重复，不予放行");
            return false;
        } else {//缓存这个请求 id ，方便以后检查
            this.redisTemplate.opsForHash().put(this.reqIdKeyProperties.getPrefix(), reqId, 1);

            //每次请求都设置 key 的过期时间，好像没必要，应该只有第一个请求 id 需要设置，可能弄一个定时任务定时删除更合适吧

            if (ThreadLocalRandom.current().nextInt(100) == 0) {//随机数是0，要设置过期时间
                this.redisTemplate.expire(this.reqIdKeyProperties.getPrefix(), this.reqIdKeyProperties.getExpiry(), TimeUnit.MINUTES);
            }

        }

        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
    }
}
